// ExtractGUI.cpp

#include "StdAfx.h"

#include "Common/String/StringConvert.h"

#include "Common/System/Error.h"
#include "Common/FileSystem/FileDir.h"
#include "Common/FileSystem/FileFind.h"

#include "../FileManager/ExtractCallback.h"
#include "Common/String/FormatUtils.h"
#include "Common/Lang/LangUtils.h"
//#include "../FileManager/resourceGui.h"
#include "../FileManager/resource.h"

#include "Common/Archive/ArchiveExtractCallback.h"
#include "Common/Props/PropIDUtils.h"

#include "../Explorer/MyMessages.h"

#include "resource2.h"
#include "ExtractRes.h"

#include "ExtractDialog.h"
#include "ExtractGUI.h"

using namespace Common;
using namespace Archive;
using namespace FileSystem;

static const wchar_t *kIncorrectOutDir = _T("Incorrect output directory path");

#ifndef _SFX

static void AddValuePair(UINT resourceID, UINT32 langID, UINT64 value, CString &s)
{
  TCHAR sz[32];
  s += Lang::LangString(resourceID, langID);
  s += _T(' ');
  _ui64tot(value, sz, 10);
  s += sz;
  s += _T('\n');
}

static void AddSizePair(UINT resourceID, UINT32 langID, UINT64 value, CString &s)
{
  TCHAR sz[32];
  s += Lang::LangString(resourceID, langID);
  s += _T(' ');
  _ui64tot(value, sz, 10);
  s += sz;
  _ui64tot(value >> 20, sz, 10);
  s += _T(" (");
  s += sz;
  s += _T(" MB)");
  s += _T('\n');
}

#endif

class CThreadExtracting: public CProgressThreadVirt
{
  HRESULT ProcessVirt();
public:
  CCodecs *codecs;
  CExtractCallbackImp *ExtractCallbackSpec;
  std::vector<int> FormatIndices;

  std::vector<CString> *ArchivePaths;
  std::vector<CString> *ArchivePathsFull;
  const Common::FileSystem::Wildcard::CCensorNode *WildcardCensor;
  const Common::Archive::CExtractOptions *Options;
  CComPtr<IExtractCallbackUI> ExtractCallback;
  CString Title;

  CThreadExtracting(CProgressThreadVirt::ThreadPoolType * pool) :
	  CProgressThreadVirt(pool)
  {}
};

HRESULT CThreadExtracting::ProcessVirt()
{
  Common::Archive::CDecompressStat Stat;
  HRESULT res = DecompressArchives(codecs, FormatIndices, *ArchivePaths, *ArchivePathsFull,
      *WildcardCensor, *Options, ExtractCallbackSpec, ExtractCallback, ErrorMessage, Stat);
  #ifndef _SFX
  if (Options->TestMode && ExtractCallbackSpec->IsOK())
  {
    CString s;
    AddValuePair(IDS_ARCHIVES_COLON, 0x02000324, Stat.NumArchives, s);
    AddValuePair(IDS_FOLDERS_COLON, 0x02000321, Stat.NumFolders, s);
    AddValuePair(IDS_FILES_COLON, 0x02000320, Stat.NumFiles, s);
    AddSizePair(IDS_SIZE_COLON, 0x02000322, Stat.UnpackSize, s);
    AddSizePair(IDS_COMPRESSED_COLON, 0x02000323, Stat.PackSize, s);
    
    if (Options->CalcCrc)
    {
      wchar_t temp[16];
      Props::ConvertUInt32ToHex(Stat.CrcSum, temp);
      s += _T("CRC: ");
      s += temp;
      s += _T('\n');
    }
    
    s += _T('\n');
    s += Lang::LangString(IDS_MESSAGE_NO_ERRORS, 0x02000608);
    
    OkMessageTitle = Title;
    OkMessage = s;
  }
  #endif
  return res;
}

HRESULT ExtractGUI(
    CCodecs *codecs,
    const std::vector<int> &formatIndices,
    std::vector<CString> &archivePaths,
    std::vector<CString> &archivePathsFull,
    const Wildcard::CCensorNode * const wildcardCensor,
    Common::Archive::CExtractOptions &options,
    bool showDialog,
    bool &messageWasDisplayed,
    CExtractCallbackImp *extractCallback,
	std::shared_ptr<Common::System::Threading::CSimpleWorkerPool> * pool,
    HWND hwndParent)
{
	ATLASSERT(NULL != wildcardCensor);
  messageWasDisplayed = false;

  CThreadExtracting extracter(pool);
  extracter.codecs = codecs;
  extracter.FormatIndices = formatIndices;

  if (!options.TestMode)
  {
    CString outputDir = options.OutputDir;
    #ifndef UNDER_CE
    if (outputDir.IsEmpty())
      Common::FileSystem::GetCurrentDirectory(outputDir);
    #endif
    if (showDialog)
    {
      CExtractDialog dialog;
      if (!Common::FileSystem::GetFullPathName(outputDir, dialog.DirectoryPath))
      {
        ShowErrorMessage(kIncorrectOutDir);
        messageWasDisplayed = true;
        return E_FAIL;
      }
      FileSystem::FileName::NormalizeDirPathPrefix(dialog.DirectoryPath);

      if (dialog.DoModal(hwndParent) != IDOK)  
				return E_ABORT;
      outputDir = dialog.DirectoryPath;
      options.OverwriteMode = dialog.OverwriteMode;
      options.PathMode = dialog.PathMode;
      #ifndef _SFX
      extractCallback->Password = dialog.Password;
      extractCallback->PasswordIsDefined = !dialog.Password.IsEmpty();
      #endif
    }
    if (!Common::FileSystem::GetFullPathName(outputDir, options.OutputDir))
    {
      ShowErrorMessage(kIncorrectOutDir);
      messageWasDisplayed = true;
      return E_FAIL;
    }
	FileSystem::FileName::NormalizeDirPathPrefix(options.OutputDir);
    
    /*
    if(!NFile::NDirectory::CreateComplexDirectory(options.OutputDir))
    {
      CString s = GetUnicodeString(NError::FormatMessage(GetLastError()));
      CString s2 = FormatNew(IDS_CANNOT_CREATE_FOLDER,
      #ifdef LANG
      0x02000603,
      #endif
      options.OutputDir);
      MessageBox(s2 + CString(L'\n') + s);
      return E_FAIL;
    }
    */
  }
  
  CString title = Lang::LangStringSpec(options.TestMode ? IDS_PROGRESS_TESTING : IDS_PROGRESS_EXTRACTING,
      options.TestMode ? 0x02000F90: 0x02000890);

  extracter.Title = title;
  extracter.ExtractCallbackSpec = extractCallback;
  extracter.ExtractCallbackSpec->ProgressDialog = &extracter.ProgressDialog;
  extracter.ExtractCallback = extractCallback;
  extracter.ExtractCallbackSpec->Init();

  extracter.ProgressDialog.CompressingMode = false;

  extracter.ArchivePaths = &archivePaths;
  extracter.ArchivePathsFull = &archivePathsFull;
  extracter.WildcardCensor = wildcardCensor;
  extracter.Options = &options;

  extracter.ProgressDialog.IconID = IDI_ICON;

  HRESULT hRes = extracter.Create(title, hwndParent);
  if(S_OK != hRes)
	return hRes;
  messageWasDisplayed = extracter.ThreadFinishedOK &
      extracter.ProgressDialog.MessagesDisplayed;
  return extracter.Result;
}
